/*
 * JSF Toolkit Component Framework
 * Copyright (C) 2007 Noah Sloan <iamnoah A-T gmail D0T com>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 */
package com.jsftoolkit.gen.config;

import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Utility methods for manipulating a DOM tree.
 * 
 * @author noah
 * 
 */
public class DomUtils {

	/**
	 * Create the given element and set its content.
	 * 
	 * @param doc
	 * @param tagName
	 * @param textContent
	 * @return
	 */
	public static Element newElement(Document doc, String tagName,
			String textContent) {
		Element e = doc.createElement(tagName);
		e.setTextContent(textContent);
		return e;
	}

	/**
	 * 
	 * @param doc
	 *            the document being parsed
	 * @param pathExpression
	 *            the xpath to find the node
	 * @param elementName
	 *            the name of the element tag
	 * @param siblingExpression
	 *            the xpath for finding the node that this element should be
	 *            inserted before (or null if there isn't one)
	 * @return the element
	 * @throws XPathExpressionException
	 */
	public static Element findOrCreateElement(Document doc, Element parent,
			XPathExpression pathExpression, String elementName,
			XPathExpression siblingExpression) throws XPathExpressionException {
		Node found = findNode(parent, pathExpression);
		Element e;
		if (found == null) {
			e = doc.createElement(elementName);
			parent.insertBefore(e, findNode(parent, siblingExpression));
		} else {
			e = (Element) found;
		}
		return e;
	}

	/**
	 * Sets the text value of the child element with the given tag name,
	 * creating it if it doesn't exist.
	 * 
	 * @param doc
	 * @param parent
	 * @param tagName
	 * @param value
	 * @return
	 */
	public static Element setElementValue(Document doc, Element parent,
			String tagName, String value) {
		NodeList elements = parent.getElementsByTagName(tagName);
		Element e = null;
		if (elements.getLength() > 0) {
			e = (Element) elements.item(0);
			if (value == null) {
				e.getParentNode().removeChild(e);
				e = null;
			} else {
				e.setTextContent(value);
			}
		} else if (value != null) {
			e = newElement(doc, tagName, value);
			parent.appendChild(e);
		}
		return e;
	}

	/**
	 * 
	 * @param ctx
	 * @param expression
	 * @return the first node to match expression, relative to ctx
	 * @throws XPathExpressionException
	 */
	public static Node findNode(Element ctx, XPathExpression expression)
			throws XPathExpressionException {
		return expression == null ? null : (Node) expression.evaluate(ctx,
				XPathConstants.NODE);
	}

	/**
	 * 
	 * @param ctx
	 * @param expression
	 * @return the list of nodes that match expression relative to ctx
	 * @throws XPathExpressionException
	 */
	public static NodeList find(Element ctx, XPathExpression expression)
			throws XPathExpressionException {
		return (NodeList) expression.evaluate(ctx, XPathConstants.NODESET);
	}

}
